#include "World.h"
	class Coordinate;
	World::World(void)
		:Component("World")
	{
		D3DXCreateTextureFromFile(g_pd3dDevice,"./Res/World/Cell.png",&m_curTex);
		m_curVb=NULL;
		m_wWidth=0;
		m_figMove=false;
		m_wHeight=0;
		m_move=false;
		m_moveCount=0;
		m_curCell.x=-1;
		m_curCell.y=-1;
	}

	World::~World(void)
	{
	}

	void World::addedToObject()
	{
		//requestMessage("InitFight");
		requestMessage("InitFightData",&World::InitWorld);
		requestMessage("AddFigureInWorld",&World::AddFigureInCell);
		requestMessage("RenderWorld",&World::Draw);
		requestMessage("RenderFigureInWorld",&World::TransformCell);
		requestMessage("RenderMoveCell",&World::RenderMoveCell);
		requestMessage("UpdateCursor",&World::UpdateCursorCell);
		requestMessage("GetCellPos",&World::GetCurCellPos);
		requestMessage("ClickedMovePos",&World::FigureMove);
		requestMessage("ClearMoveCell",&World::ClearMove);
	}

	void World::FigureMove(const Message & msg)
	{
		vector<boost::any>* pa=boost::any_cast<vector<boost::any>*>(msg.p);
		vector<boost::any>::iterator iter=pa->begin();
		bool* rt=boost::any_cast<bool*>(*iter);
		if(m_cell[m_curCell.x][m_curCell.y].move&&m_cell[m_curCell.x][m_curCell.y].fid==-1)
		{
			*rt=true;
			m_figMove=true;
			sendMessage("FigureMove",m_curCell);
		}
	}

	void World::UpdateFigurePos(WorldPoint wp)
	{
		m_cell[m_curCell.x][m_curCell.y].fid=m_cell[wp.x][wp.y].fid;
		m_cell[wp.x][wp.y].fid=-1;
	}
	
	void World::ClearMove(const Message & msg)
	{
		m_moveVB->Release();
		m_move=false;
		m_moveCount=0;

		for(int32 i=0;i<m_wHeight;i++)
		{
			for(int32 j=0;j<m_wWidth;j++)
			{
				m_cell[i][j].move=false;
			}
		}
	}

	void World::RenderMoveCell(const Message & msg)
	{
		m_move=true;
		m_moveCount=0;
		FIGURE fg=boost::any_cast<FIGURE>(msg.p);
		int32 x=fg.pos.x;
		int32 y=fg.pos.y;
		int32 move=fg.fa.move;
		int32 _x=x-move;
		int32 _y=y-move;
		for(int32 i=0;i<=move;i++)
		{
			if((_x+i)<0||(_x+i)>m_wWidth)
			{
				continue;
			}

			for(int32 j=0;j<2*i+1;j++)
			{
				if((y+j-i)<0||(y+j-i)>m_wWidth)
				{
					continue;
				}
				m_cell[_x+i][y+j-i].move=true;
				m_moveCount++;

			}
		}
		for(int32 i=0;i<move;i++)
		{
			if((x+1+i)<0||(x+1+i)>m_wWidth)
			{
				continue;
			}
			for(int32 j=0;j<2*(move-i)-1;j++)
			{
				if((_y+i+1+j)<0||(_y+i+1+j)>m_wWidth)
				{
					continue;
				}
				m_cell[x+1+i][_y+i+1+j].move=true;
				m_moveCount++;
			}
		}

		CreateMoveCell();
	}

	void World::TransformCell(const Message & msg)
	{
		WorldPoint* p=boost::any_cast<WorldPoint*>(msg.p);
		D3DXMATRIXA16 matWorld;
		D3DXMatrixIdentity( &matWorld );
		if(m_figMove&&*p==m_moveEnd)
		{
			D3DXVECTOR3 moveStart=GetCellPos(m_moveStart.x,m_moveStart.y);
			D3DXVECTOR3 moveEnd=GetCellPos(m_moveEnd.x,m_moveEnd.y);
			if((moveStart.x+m_moveInc.x-moveEnd.x)>=0.001f||
				(moveStart.x+m_moveInc.x-moveEnd.x)<=-0.001f
				)
				if(moveStart.x>moveEnd.x)
					m_moveInc.x-=0.1f;
				else
					m_moveInc.x+=0.1f;
			else if((moveStart.z+m_moveInc.z-moveEnd.z)>=0.001f||
				(moveStart.z+m_moveInc.z-moveEnd.z)<=-0.001f)
				if(moveStart.z>moveEnd.z)
					m_moveInc.z-=0.1f;
				else
					m_moveInc.z+=0.1f;
			moveStart+=m_moveInc;
			D3DXMatrixTransformation(&matWorld,NULL,NULL,NULL,NULL,NULL,&moveStart);
		}
		else
		{
			D3DXVECTOR3 pos=GetCellPos(p->x,p->y);
			D3DXMatrixTransformation(&matWorld,NULL,NULL,NULL,NULL,NULL,&pos);
		}
		g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
	}

	int32 World::GetCurCellFid()
	{
		return m_cell[m_curCell.x][m_curCell.y].fid;
	}

	void World::AddFigureInCell(const Message & msg)
	{
		FIG_POS* fp=boost::any_cast<FIG_POS*>(msg.p);
		if(m_cell[fp->x][fp->y].fid!=-1)
			return ;
		m_cell[fp->x][fp->y].fid=fp->fid;
	}

	void World::GetCurCellPos(const Message & msg)
	{
		vector<boost::any>* pa=boost::any_cast<vector<boost::any>*>(msg.p);
		vector<boost::any>::iterator iter=pa->begin();
		D3DXVECTOR3* pos=boost::any_cast<D3DXVECTOR3*>(*iter++);
		int32* fid=boost::any_cast<int32*>(*iter++);
		if(m_cell[m_curCell.x][m_curCell.y].fid==-1)
		{
			*pos=D3DXVECTOR3(0.0f,0.0f,0.0f);
			return;
		}
		*pos=m_cell[m_curCell.x][m_curCell.y].midPos;
		*fid=m_cell[m_curCell.x][m_curCell.y].fid;
	}

	D3DXVECTOR3 World::GetCellPos(int32 x,int32 y)
	{
		if(!CheckCell(x,y))
			return D3DXVECTOR3(0.0f,0.0f,0.0f);
		return m_cell[x][y].midPos;
	}

	bool World::CheckCell(int32 x,int32 y)
	{
		if(x<0||y<0||x>=m_wWidth||y>=m_wHeight)
			return false;
		return true;
	}

	void World::InitWorld(const Message &msg)
	{
		sendMessage("LoadMap");
		InitCell();
		CreateGround();
	}

	bool World::GetCellIndex(D3DXVECTOR3 pos,int32* x,int32* y)
	{
		for(int i=0;i<m_wHeight;i++)
		{
			for(int j=0;j<m_wWidth;j++)
			{
				if(pos.x>m_cell[i][j].minPos.x
					&&pos.y>m_cell[i][j].minPos.y
					&&pos.z>m_cell[i][j].minPos.z
					&&pos.x<m_cell[i][j].maxPos.x
					&&pos.y<m_cell[i][j].maxPos.y
					&&pos.z<m_cell[i][j].maxPos.z)
				{
					*x=i;
					*y=j;
					return true;
				}
			}
		}
		return false;
	}

	bool World::LoadGround(int32 w, int32 h, const char* fname)
	{
		m_wWidth=w;
		m_wHeight=h;
		m_sWidth=w*WIDTH_PRE_CELL;
		m_sHeight=h*WIDTH_PRE_CELL;
		if(D3DXCreateTextureFromFile(g_pd3dDevice,fname,&m_tex))
			return false;
		return true;
	}

	void World::InitCell()
	{
		D3DXVECTOR3 pos=D3DXVECTOR3(WIDTH_PRE_CELL/2,0.0f,WIDTH_PRE_CELL/2);
		D3DXVECTOR3 inc=pos;
		for(int i=0;i<m_wHeight;i++)
		{
			for(int j=0;j<m_wWidth;j++)
			{
				m_cell[i][j].midPos=pos;
				m_cell[i][j].minPos=pos-inc;
				m_cell[i][j].maxPos=pos+inc;
				m_cell[i][j].fid=-1;
				m_cell[i][j].move=false;
				pos.x+=WIDTH_PRE_CELL;
			}
			pos.x=WIDTH_PRE_CELL/2; 
			pos.z+=WIDTH_PRE_CELL;
		}
	}

	void World::UpdateCursorCell(const Message & msg)
	{
		D3DXVECTOR2 spos=boost::any_cast<D3DXVECTOR2>(msg.p);
		Ray* mouseRay=Coordinate::Instance()->ScreenToWorldCoord(&spos);
		D3DXVECTOR3 wpos;
		if(!mouseRay->Intersects(Plane(D3DXVECTOR3(0,1,0),0),&wpos))
		{
			return;
		}
		int32 x=wpos.x;
		int32 z=wpos.z;
		if(x<0||x>=m_wWidth*WIDTH_PRE_CELL
			||z<0||z>=m_wHeight*WIDTH_PRE_CELL)
			return ;
		x-=x%(int32)WIDTH_PRE_CELL;
		z-=z%(int32)WIDTH_PRE_CELL;
		wpos.x=x,wpos.y=0;wpos.z=z;
		int32 iw=x/(int32)WIDTH_PRE_CELL;
		int32 ih=z/(int32)WIDTH_PRE_CELL;
		m_curCell.x=ih;
		m_curCell.y=iw;
		if( FAILED( g_pd3dDevice->CreateVertexBuffer( 6*sizeof( CUSTOMVERTEX ),
			D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX,
			D3DPOOL_DEFAULT, &m_curVb, NULL ) ) )
		{
			return ;
		}

		CUSTOMVERTEX* pVertices;

		if( FAILED( m_curVb->Lock( 0, 0, ( void** )&pVertices, 0 ) ) )
			return ;

		CreateQuad(&wpos,pVertices,0);

		m_curVb->Unlock();
	}

	HRESULT World::CreateMoveCell()
	{
		if(FAILED(g_pd3dDevice->CreateVertexBuffer(6*m_wWidth*m_wHeight*sizeof(CUSTOMVERTEX),
			D3DUSAGE_WRITEONLY ,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&m_moveVB,NULL)))
		{
			return E_FAIL;
		}
		int32 c=0;
		CUSTOMVERTEX* pMoveVertices;
		if( FAILED( m_moveVB->Lock( 0, 0, ( void** )&pMoveVertices, 0 ) ) )
			return E_FAIL;
		for(int32 i=0;i<m_wHeight;i++)
		{
			for(int32 j=0;j<m_wWidth;j++)
			{
				if(m_cell[i][j].move)
				{
					CreateQuad(&m_cell[i][j].minPos,pMoveVertices,c++);
				}
			}
		}
		m_moveVB->Unlock();
		return S_OK;
	}

	void World::SetFigureMove(WorldPoint wp)
	{
		m_cell[m_curCell.x][m_curCell.y].fid=m_cell[wp.x][wp.y].fid;
		m_cell[wp.x][wp.y].fid=-1;
		m_moveStart=wp;
		m_moveEnd=m_curCell;
		m_moveInc.x=0;
		m_moveInc.y=0;
		m_moveInc.z=0;
	}

	HRESULT World::CreateGround()
	{
		// Buffer to hold vertices
		if( FAILED( g_pd3dDevice->CreateVertexBuffer( 6*m_wWidth*m_wHeight*sizeof( CUSTOMVERTEX ),
			D3DUSAGE_WRITEONLY , D3DFVF_CUSTOMVERTEX,
			D3DPOOL_DEFAULT, &m_groundVB, NULL ) ) )
		{
			return E_FAIL;
		}

		CUSTOMVERTEX* pVertices;

		if( FAILED( m_groundVB->Lock( 0, 0, ( void** )&pVertices, 0 ) ) )
			return E_FAIL;

		D3DXVECTOR3 pos=D3DXVECTOR3(0.0f,0.0f,0.0f);
		for(int32 i=0;i<m_wHeight;i++)
		{
			for(int32 j=0;j<m_wWidth;j++)
			{
				CreateQuad(&pos,pVertices,i*m_wWidth+j);
				pos.x+=WIDTH_PRE_CELL;
			}
			pos.z+=WIDTH_PRE_CELL;
			pos.x=0.0f;

		}
		m_groundVB->Unlock();

		return S_OK;
	}

	void World::DrawGround()
	{
		g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
		D3DXMATRIXA16 matWorld;
		D3DXMatrixIdentity( &matWorld );
		g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

		g_pd3dDevice->SetTexture( 0,m_tex);

		g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
		g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
		g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );

		g_pd3dDevice->SetRenderState(D3DRS_ALPHAREF,(DWORD)0x000000A5);
		g_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL);
		g_pd3dDevice->SetStreamSource( 0, m_groundVB, 0, sizeof( CUSTOMVERTEX ) );
		g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
		//g_pd3dDevice->SetIndices(m_id);
		//g_pd3dDevice->DrawIndexedPrimitive(   D3DPT_TRIANGLESTRIP    , 0,0,4*m_wWidth*m_wHeight,0,6*m_wWidth*m_wHeight);
		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,2*m_wWidth*m_wHeight);

		if(m_move)
		{
			g_pd3dDevice->SetTexture( 0,m_curTex);
			g_pd3dDevice->SetStreamSource( 0, m_moveVB, 0, sizeof( CUSTOMVERTEX ) );
			g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,m_moveCount*2);
		}



		if(m_curTex!=NULL&&m_curVb!=NULL)
		{
			g_pd3dDevice->SetTexture( 0,m_curTex);
			g_pd3dDevice->SetStreamSource( 0, m_curVb, 0, sizeof( CUSTOMVERTEX ) );
			g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);
		}

		// End the scene
		g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
	}

	void World::Draw(const Message & msg)
	{
		DrawGround();
		//m_Figure->RenderFigure(t);
	}